package de.game.graph;

import java.util.ArrayList;

public class GraphImpl implements Graph{

	/**
	 * @param args
	 */
	
	private int id;
	private String name;
	private ArrayList<Node> nodes = new ArrayList<Node>();
	private ArrayList<Edge> edges = new ArrayList<Edge>();
	private Node root;
	
	
	
	public GraphImpl(){
		
	}
	
	public GraphImpl(String name, int id, ArrayList<Node> nodes, ArrayList<Edge> edges, Node root){
		this.name = name;
		this.id = id;
		this.nodes = nodes;
		this.edges = edges;
		this.root = root;
	}
	
	
	
	@Override
	public Graph createGraph(String name, int ID, ArrayList<Node> nodes, ArrayList<Edge> edges,
			Node root) {
		return new GraphImpl(name, ID, nodes, edges, root);
	}

	@Override
	public String getName() {
		return name;
	}

	
	private int getID(){
		return id;
	}
	
	@Override
	public ArrayList<Edge> getEdges() {
		return edges;
	}

	@Override
	public void addEdge(Edge e) {

		if(edges.size() == 0){
			edges.add(e);
			nodes.add(e.getStartNode());
			nodes.add(e.getEndNode());
		} 
	}

	
	
	@Override
	public Edge getEdge(String name, int ID)   {
		Edge t = null;
		if(name.equals(null)){
			for(Edge a : edges){
				if(ID == a.getID()){
					t = a;
				} else {
					try {
						throw new NodeNotFoundException("Edge not found");
					} catch (NodeNotFoundException e) {}
				}
			}
			
		} else {
			for(Edge a : edges){
				if(name == a.getName()){
					t =a;
				} else {
					try {
						throw new NodeNotFoundException("Edge not found");
					} catch (NodeNotFoundException e) {	}
				}}
			}
		
		return t;
	}

	
	
	
	@Override
	public void removeEdge(Edge e) {
				//		TODO
	}

	
	@Override
	public ArrayList<Node> getNodes() {
		return nodes;
	}

	@Override
	public void addNode(Node n) { 
		
		if(!nodes.contains(n)){
				nodes.add(n);
				for(Node a : n.getNeighbours()){
					if(!nodes.contains(a)){
						nodes.add(a);
					}
				}
				for(Edge b : n.getEdges()){
					if(!edges.contains(b)){
						edges.add(b);
					}
				}
		}
	}
	
	
	/**
	 * Methode, die rekursiv alle Nodes angefangen von der Wurzel an einen Graphen addet.
	 */
	@Override
	public void addAllNodesFromRoot(Node root){ 
		

		if(!NodeImpl.contains(nodes, root)){
			nodes.add(root);
				for(Node a : root.getNeighbours()){
					if(!nodes.contains(a)){
						addAllNodesFromRoot(a);
					}
				}
				for(Edge b : root.getEdges()){
					if(!edges.contains(b)){
						edges.add(b);
					}
				}
		}
	}
	
		
	@Override
	public Node getNode(String name, int ID) {
		Node t = null;	
		
		for(Node a : nodes){
				if(a.getName().equals(name) && a.getID() == ID){
					t = a;;
				} else {
					try {
						throw new NodeNotFoundException("Node not Found");
					} catch (NodeNotFoundException e) {	}
				}
			}
		return t;	
		
	}

	
	@Override
	public void removeNode(Node n) {
		if(nodes.contains(n)){
			nodes.remove(n);
			if(n.equals(getRoot())){
				setRoot(n.getNeighbours().get(0));
			}
			for(Edge a : n.getEdges()){
				if(n.equals(a.getStartNode())){
					a.getEndNode().removeEdge(a);
				} else {
					a.getStartNode().removeEdge(a);
				}
				edges.remove(a);
			}
			
		}
	}

	@Override
	public void setRoot(Node n) {
		root = n;
		
	}

	@Override
	public Node getRoot() {
		return root;
	}

	@Override
	public boolean isTree() {
		
		return false;
	}

	
	@Override
	public String toString(){
		
		String nodeData = "";
		String edgeData = "";
		
		for(Node a : nodes){
			nodeData = nodeData + a.toString()+ "\n ---- \n";
		}
		for(Edge a : edges){
			edgeData = edgeData + a.toString()+ "\n ---- \n";
		}
		
		return("The Name of the Graph is "+ this.getName()+ " and its ID is "+ this.getID()+" \n" +
				"Its root is "+ this.getRoot().getName()+ " his nodes are: \n"+nodeData+ " and his edges are:\n " +
					edgeData+	".");
		
		
	}
	
	@Override
	public void getForgottenNodes(Graph g){
		ArrayList<Node> temp = new ArrayList<Node>();
		for(Node a : g.getNodes()){
			if(!this.getNodes().contains(a)){
				temp.add(a);
			}
		}
		System.out.println("tempSIZE: "+temp.size());
		for(Node a : temp){
			System.out.println(a.getName()+"|");
		}
	}

	
}
